﻿#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;


/*
给定一个三角形 triangle ，找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
也就是说，如果正位于当前行的下标 i ，那么下一步可以移动到下一行的下标 i 或 i + 1 。


示例 1：
输入：triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出：11
解释：如下面简图所示：
   2
  3 4
 6 5 7
4 1 8 3
自顶向下的最小路径和为 11（即，2 + 3 + 5 + 1 = 11）。

示例 2：
输入：triangle = [[-10]]
输出：-10
 

提示：
1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104
 

进阶：
你可以只使用 O(n) 的额外空间（n 为三角形的总行数）来解决这个问题吗？
*/



/*
[
[-7],
[-2,1],
[-5,-5,9],
[-4,-5,4,4],
[-6,-6,2,-1,-5],
[3,7,8,-3,7,-9],
[-9,-1,-9,6,9,0,7],
[-7,0,-6,-8,7,1,-4,9],
[-3,2,-6,-9,-7,-6,-9,4,0],
[-8,-6,-3,-9,-2,-6,7,-5,0,7],
[-9,-1,-2,4,-2,4,4,-1,2,-5,5],
[1,1,-6,1,-2,-4,4,-2,6,-6,0,6],
[-3,-3,-6,-2,-6,-2,7,-9,-5,-7,-5,5,1]
]
*/





class Solution {
public:
	int minimumTotal(vector<vector<int>>& triangle) {
		int m = triangle.size(); int n = triangle[0].size();
		vector<vector<int>> dp(m + 10, vector<int>(m + 10));

		for (int i = 0; i < m; i++) {
			for (int j = 0; j < m; j++) {
				dp[i][j] = 999999999;
			}
		}

		dp[0][0] = triangle[0][0];

		for (int i = 1; i < m; i++) {
			for (int j = 0; j <= i; j++) {
				if (i > 0 && j < i) {
					dp[i][j] = min(dp[i][j], dp[i - 1][j]);
				}
				if (i > 0 && j > 0) {
					dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]);
				}
				dp[i][j] += triangle[i][j];
			}
		}

		int ans = 99999999;
		for (int i = 0; i < m; i++) {
			ans = min(ans, dp[m - 1][i]);
		}

		return ans;
	}
};




//
//int main() {
//
//	Solution s;
//	vector<vector<int>> vv{
//		{-7},
//		{-2,1},
//		{-5,-5,9},
//		{-4,-5,4,4},
//		{-6,-6,2,-1,-5},
//		{3,7,8,-3,7,-9},
//		{-9,-1,-9,6,9,0,7},
//		{-7,0,-6,-8,7,1,-4,9},
//		{-3,2,-6,-9,-7,-6,-9,4,0},
//		{-8,-6,-3,-9,-2,-6,7,-5,0,7},
//		{-9,-1,-2,4,-2,4,4,-1,2,-5,5},
//		{1,1,-6,1,-2,-4,4,-2,6,-6,0,6},
//		{-3,-3,-6,-2,-6,-2,7,-9,-5,-7,-5,5,1}
//	};
//	cout << s.minimumTotal(vv);
//
//
//	return 0;
//}